package org.infodavid.common.util;

import java.lang.ref.WeakReference;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.infodavid.common.util.IVisitor.IResult;

/**
 * The Class HelperUtil.
 */
public final class HelperUtil {

  /** The Constant log. */
  private static final Log LOGGER = LogFactory.getLog(HelperUtil.class);

  /** The singleton. */
  private static WeakReference<HelperUtil> singleton = null;

  /**
   * returns the singleton.
   * @return <code>HelperUtil</code>
   */
  public static synchronized HelperUtil getInstance() {
    if (singleton == null || singleton.get() == null) {
      singleton = new WeakReference<HelperUtil>(new HelperUtil());
    }

    return singleton.get();
  }

  /**
   * Instantiates a new utility.
   */
  private HelperUtil() {
    super();
  }

  /**
   * Execute.
   * @param visitor the visitor
   * @param data the data
   * @param retryCount the retry count
   * @param retryPeriod the retry period
   * @throws Throwable the error
   */
  public <I extends Object,O extends Object> IResult<O> execute(final IVisitor<I,O> visitor,
      final I data, final int retryCount, final long retryPeriod) throws Throwable {
    IResult<O> result = null;
    int retries = 0;

    do {
      try {
        result = visitor.visit(data);
      }
      catch (final Throwable e) {
        retries++;

        if (retries < retryCount) {
          LOGGER.warn("An error occurs while sending of the messages (retry=" + retries
              + "), retrying after " + retryPeriod + " ms", e);

          try {
            Thread.sleep(retryPeriod);
          }
          catch (final InterruptedException e1) {
            LOGGER.warn("An error occurs while setting retry period", e1);
          }
        }
        else {
          throw e;
        }
      }
    }
    while (result == null && retries < retryCount);

    return result;
  }
}
